package de.dnb.basics;

import static de.dnb.basics.applicationComponents.StringUtils.getPicaPlusContent;

import java.awt.Component;
import java.awt.print.PrinterException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.jar.JarFile;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;

import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import de.dnb.basics.applicationComponents.RangeCheckUtils;
import de.dnb.basics.utils.HTMLUtils;
import de.dnb.basics.utils.PortalUtils;
import de.dnb.gnd.utils.RecordUtils;

public class Misc {

	public static boolean isServerError(int httpCode) {
		return httpCode >= 500 && httpCode < 600;
	}

	public static boolean isClientError(int httpCode) {
		return httpCode >= 400 && httpCode < 500;
	}

	public static boolean httpError(int httpCode) {
		return httpCode >= 400;
	}

	/**
	 * Fabriziert aus der Idn eine Portal-URI.
	 * 
	 * @param idn	nicht null.
	 * @return			null, wenn keine Verbindung zum Portal aufgebaut
	 * 					werden konnte.
	 */
	public static String createURI(final String idn) {
		RangeCheckUtils.assertReferenceParamNotNull("idn", idn);

		String uri = "http://d-nb.info/" + idn;
		URL url = null;
		HttpURLConnection conn;
		try {
			url = new URL(uri);
			conn = (HttpURLConnection) url.openConnection();
			if (httpError(conn.getResponseCode())) {
				uri =
					"http://dispatch.opac.d-nb.de/" + "DB=1.1/SET=4/TTL=1/"
						+ "CMD?ACT=SRCHA&IKT=8509&SRT=LST_ty&TRM=idn+" + idn;
				url = new URL(uri);
				conn = (HttpURLConnection) url.openConnection();
				if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
					return null;
				}
			}
		} catch (IOException e) {
			return null;
		}
		return uri;
	}

	/**
	 * dummerweise ist das kein valider xml-Code. Daher nach Pattern suchen.
	 * Nach dem Wort "Sachgruppe(n)" folgen einige Formatierungs-Tags und
	 * Umbrüche, danach die Ziffern. Sachgruppen K und S werden 
	 * ausgeschlossen.
	 * 
	 * DOTALL matcht auch Zeilenumbrüche.
	 */
	private static final String SACHGRUPPE_PAT =
		"Sachgruppe[^0-9KS]*?(\\d\\d\\d(\\.\\d+)?)\\D";

	private static final String SACHGRUPPE_K_PAT =
		"Sachgruppe\\D*?(K) Kinder- und Jugendliteratur";

	private static final String SACHGRUPPE_S_PAT =
		"Sachgruppe\\D*?(S) Schulbücher";

	private static Pattern sgPat = Pattern.compile(SACHGRUPPE_PAT,
		Pattern.DOTALL);

	private static Pattern sgKPat = Pattern.compile(SACHGRUPPE_K_PAT,
		Pattern.DOTALL);

	private static Pattern sgSPat = Pattern.compile(SACHGRUPPE_S_PAT,
		Pattern.DOTALL);

	/**
	 * Sucht sich aus der Portalanzeige die Sachgruppe zusammen.
	 * 
	 * @param idn	nicht null.
	 * @return		null, wenn nichts gefunden.
	 */
	public static String getSachgruppe(final String idn) {
		String title = PortalUtils.getRecordViaPortal(idn);
		if (title == null)
			return null;
		Matcher m = sgPat.matcher(title);
		if (m.find())
			return m.group(1);
		m = sgKPat.matcher(title);
		if (m.find())
			return m.group(1);
		m = sgSPat.matcher(title);
		if (m.find())
			return m.group(1);
		return null;
	}

	/**
	 * Liefert den Inhalt der Website.
	 * @param uri	nicht null, nicht leer
	 * @return		null, wenn nichts gefunden wurde
	 */
	public static String getWebsite(final String uri) {
		RangeCheckUtils.assertStringParamNotNullOrEmpty("uri", uri);
		String website = "";
		try {
			URL url = new URL(uri);
			BufferedReader br1 =
				new BufferedReader(new InputStreamReader(url.openStream()));
			String read;
			while ((read = br1.readLine()) != null) {
				website += read + Constants.LINE_SEPARATOR;
			}
		} catch (IOException e) {
			return null;
		}
		return website;
	}

	/**
	 * Gibt einen Infotext aus. 
	 * @param component	Aufrufendes Objekt (this)
	 * @param version	Versionsnummer
	 * @param file 		Pfad zur Hilfedatei
	 */
	public static void showInfo(
		final Component component,
		final String version,
		final String file) {
		SimpleDateFormat formatter =
			new SimpleDateFormat("d. M. yyyy 'um' H:mm 'Uhr'");
		Date date = getCreationDate(component);
		//					model.getCreationDate();
		String dateStr = formatter.format(date);
		String info =
			"Version " + version
				+ "\nErstellt in und für die Deutsche Nationalbibliothek"
				+ "\nAutor: Christian Baumann\n" + "Erstellungsdatum: "
				+ dateStr;
		String help = getTextFromFile(file, component);
		info += "\n" + help;
		JEditorPane ar = new JEditorPane("text/html", info);
		ar.setEditable(false);
		//		ar.setLineWrap(true);
		//		ar.setWrapStyleWord(true);
		ar.setBackground(UIManager.getColor("Label.background"));
		final JScrollPane scrollpane = new JScrollPane(ar);
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				scrollpane.getVerticalScrollBar().getModel().setValue(0);
			}
		});
		JOptionPane jOpPane =
			new JOptionPane(scrollpane, JOptionPane.PLAIN_MESSAGE);
		JDialog jDialog = jOpPane.createDialog("   Info ");
		jDialog.setSize(700, 700);
		jDialog.setLocationRelativeTo(null);
		jDialog.setResizable(true);
		jDialog.setVisible(true);
	}

	/**
	 * Gibt den Inhalt einer Datei als String. Funktioniert auch bei
	 * zip- oder jar-Files. Die Datei darf keine Umlaute enthalten.
	 * 
	 * @param file		Pfad zur Datei.
	 * @param object	aufrufendes Objekt (this)		
	 * @return			Inhalt der Datei oder null.
	 */
	public static final String getTextFromFile(
		final String file,
		final Object object) {

		BufferedReader in =
			new BufferedReader(new InputStreamReader(object.getClass()
				.getResourceAsStream(file)));

		try {
			String help = "";
			String line = in.readLine();
			while (line != null) {
				help += "\n" + line;
				line = in.readLine();
			}
			in.close();
			return help;
		} catch (Exception e) {
			StringWriter sw = new StringWriter();
			PrintWriter pw = new PrintWriter(sw);
			e.printStackTrace(pw);

			JOptionPane.showMessageDialog(null, e.getMessage(),
				"Fehler beim Helpfile", JOptionPane.OK_CANCEL_OPTION);
		}
		return null;
	}

	/**
	 * Gibt das eigene Erstellungsdatum einer jar-Datei aus.
	 * 
	 * @param object	Aufrufendes Objekt (this).
	 * @return			Datum oder null.
	 */
	public static final Date getCreationDate(final Object object) {

		/*
		 * Die Manifest-Datei der eigenen jar-Datei ist immer aktuell. Daher
		 * Zugriff auf deren URL:
		 */
		URL url = object.getClass().getResource("/META-INF/MANIFEST.MF");
		String fileStr = url.getFile();
		/*
		 * Die URL ist etwas komplizierter aufgebaut. Sie hat - ein Präfix
		 * "file:/" - ein Postfix, das mit "!" beginnt, welches die Dateien
		 * in der .jar kennzeichnet.
		 */
		int pos1 = "file:/".length();
		int pos2 = fileStr.indexOf("!");
		fileStr = fileStr.substring(pos1, pos2);
		/*
		 * fileStr enthält nun nur noch den Pfad der eigenen jar-Datei
		 */
		JarFile jarFile = null;
		Date creationDate = null;
		try {
			jarFile = new JarFile(fileStr);
			ZipEntry zEnt = jarFile.getEntry("META-INF/MANIFEST.MF");
			creationDate = new Date(zEnt.getTime());
		} catch (Exception e) {
			JOptionPane.showMessageDialog(null, e.getMessage(),
				"Fehler beim Datum", JOptionPane.OK_CANCEL_OPTION);
		} finally {
			if (jarFile != null)
				try {
					jarFile.close();
				} catch (IOException e) {
					// nix
				}
		}
		return creationDate;
	}

	/**
	 * Macht aus Rohtiteldaten einen Kurztitel.
	 * Die Rohdaten müssen im Pica+-Format vorliegen.
	 * 
	 * @param rawData	nicht null.
	 * @return			nicht null?
	 */
	public static String createShortTitle(final String rawData) {
		RangeCheckUtils.assertReferenceParamNotNull("rawData", rawData);
		String title;
		String creator;
		// 021A = 4000
		title = getPicaPlusContent("021A", 'a', rawData);
		// wohl Af:
		if (title == null) {
			//  4004 = 021B 
			String unselbstaendig = getPicaPlusContent("021B", 'a', rawData);
			title = getPicaPlusContent("021A", '8', rawData);
			if (title != null) {
				if (unselbstaendig != null)
					title = title + "; " + unselbstaendig;
			} else
				// titel immer noch null, daher letzte Rettung
				title = unselbstaendig;

			//  3010 = 028C (Person)
			creator = getPicaPlusContent("028C", '8', rawData);
			if (creator == null) {
				//  3120 = 029F (Körperschaft)
				creator = getPicaPlusContent("029F", '8', rawData);
			}
			// kein Af:
		}

		// 3000 = 028A   
		creator = getPicaPlusContent("028A", '8', rawData);
		if (creator == null) {
			// 3100 = 029A
			creator = getPicaPlusContent("029A", '8', rawData);
		}
		if (creator != null) {
			if (creator.contains("$l"))
				creator = creator.replace("$l", " <") + ">";
			if (creator.contains("$g"))
				creator = creator.replace("$g", " <") + ">";
			if (creator.contains("$b")) {
				// $gKiel$bBibliothek -> <Kiel, Bibliothek>:
				if (creator.contains("<"))
					creator = creator.replace("$b", ", ");
				else
					creator = creator.replace("$b", " <") + ">";
			}
			creator = creator.replace("$c", " ");
			title = creator + " : " + title;
		}
		title = title.replace("@", "");

		return title;

	}

	public static String createExcelHyperlink(String uri) {
		return "=HYPERLINK(\"" + uri + "\" )";
	}

	public static String createExcelHyperlink(String uri, String pretty) {
		return "=HYPERLINK(\"" + uri + "\";\"" + pretty + "\" )";
	}

	public static String createExcelLine(String... strings) {
		String s = "";
		for (int i = 0; i < strings.length; i++) {
			if (i > 0)
				s += "\t";
			String string = strings[i];
			s += string;
		}
		return s;
	}

	/**
	 * Macht aus allen Pica-Links, z.B. !040665623!, 
	 * Hyperlinks, z.B. <a href=http://040665623>040665623</a>
	 * 
	 * Die URLs können aus einem {@link JEditorPane} mit einem
	 * {@link HyperlinkListener} durch {@link HyperlinkEvent#getURL()} 
	 * ausgelesen werden. Die idn kann wiederum aus der URL durch
	 * {@link URL#getAuthority()} gewonnen werden.
	 * 
	 * @param s	nicht null
	 * @return	text mit Hyperlinks
	 */
	public static String convertLinksToHyperlinks(final String s) {
		RangeCheckUtils.assertReferenceParamNotNull("s", s);
		String text =
			RecordUtils.PAT_LINK.matcher(s).replaceAll(
				" <a href=http://$1>!$1!</a>");
		return text;
	}

	/**
	 * Extrahiert den Authority-Teil der URL und ersetzt %20 durch Blank.
	 * @param e		nicht null
	 * @return		Authority
	 */
	public static String getAuthority(HyperlinkEvent e) {
		URL url = e.getURL();
		if (url == null)
			return "";
		String name = url.getAuthority();
		return name.replace("%20", " ");
	}

	/**
	 * Expandiert oder kollabiert einen Baum.
	 * 
	 * @param tree		nicht null
	 * @param expand	expandiert, wenn true; kollabiert, wenn false
	 */
	public static void expandAll(final JTree tree, final boolean expand) {
		TreeNode root = (TreeNode) tree.getModel().getRoot();
		TreePath treePath = new TreePath(root);
		// Traverse tree from root
		if (expand)
			expandAll(tree, treePath, expand);
		else {
			TreeNode node = (TreeNode) treePath.getLastPathComponent();
			if (node.getChildCount() >= 0) {
				for (Enumeration<TreeNode> e = node.children(); e
					.hasMoreElements();) {
					TreeNode n = e.nextElement();
					TreePath path = treePath.pathByAddingChild(n);
					expandAll(tree, path, expand);
				}
			}
		}
	}

	private static void expandAll(JTree tree, TreePath parent, boolean expand) {
		// Traverse children
		TreeNode node = (TreeNode) parent.getLastPathComponent();
		if (node.getChildCount() >= 0) {
			for (Enumeration<TreeNode> e = node.children(); e.hasMoreElements();) {
				TreeNode n = e.nextElement();
				TreePath path = parent.pathByAddingChild(n);
				expandAll(tree, path, expand);
			}
		}
		// Expansion or collapse must be done bottom-up
		if (expand) {
			tree.expandPath(parent);
		} else {
			tree.collapsePath(parent);
		}
	}

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main1(String[] args) throws IOException {
		System.out.println(PortalUtils.getDNBidn("04045956X"));
	}

	/**
	 * @param args
	 * @throws IOException 
	 * @throws PrinterException 
	 */
	public static void main(final String[] args)
		throws IOException,
		PrinterException {
		HTMLUtils
			.file2Printer("D:/texte/iot5xd/Java Print Service API User Guide  1 - Introduction.htm");
	}

}
